package net.neocoin.xml;

import java.io.IOException;
import java.io.InputStream;

import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
 * {@link XPathUtilTest} 에 이 클래스의 사용 방법을 알 수 있는 테스트들이 적재되어 있습니다.
 * 
 * 
 * http://www.ibm.com/developerworks/kr/library/x-javaxpathapi.html
 * 
 * http://www.w3schools.com/xpath/default.asp
 * 
 * @since JDK 1.5
 * @author neocoin
 */
public class XPathUtil {
	public static XPathFactory xPathFactory = XPathFactory.newInstance();

	public static Document createDocument(InputStream stream) throws ParserConfigurationException, SAXException,
			IOException {
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		factory.setNamespaceAware(false); // never forget this!
		DocumentBuilder builder = factory.newDocumentBuilder();
		Document doc = builder.parse(stream);
		return doc;
	}

	public static Object evaluateXPath(Node doc, String xpathExpression, QName nodeset) throws XPathExpressionException {
		XPath xpath = xPathFactory.newXPath();
		XPathExpression expr = xpath.compile(xpathExpression);
		Object result = expr.evaluate(doc, nodeset);
		return result;
	}

	public static Object evaluateXPath(InputStream stream, String xpathExpression, QName nodeset)
			throws ParserConfigurationException, SAXException, IOException, XPathExpressionException {
		Document doc = createDocument(stream);
		return evaluateXPath(doc, xpathExpression, nodeset);
	}

	public static String evaluateToString(String xpathExpression, InputStream stream)
			throws ParserConfigurationException, SAXException, IOException, XPathExpressionException {
		return (String) evaluateXPath(stream, xpathExpression, XPathConstants.STRING);
	}

	public static NodeList evaluateToNodeList(String xpathExpression, InputStream stream)
			throws ParserConfigurationException, SAXException, IOException, XPathExpressionException {
		return (NodeList) evaluateXPath(stream, xpathExpression, XPathConstants.NODESET);
	}

	public static NodeList evaluateToNode(String xpathExpression, InputStream stream)
			throws ParserConfigurationException, SAXException, IOException, XPathExpressionException {
		return (NodeList) evaluateXPath(stream, xpathExpression, XPathConstants.NODE);
	}

	public static Double evaluateToNumber(String xpathExpression, InputStream stream)
			throws ParserConfigurationException, SAXException, IOException, XPathExpressionException {
		return (Double) evaluateXPath(stream, xpathExpression, XPathConstants.NUMBER);
	}

	public static Boolean evaluateToBoolean(String xpathExpression, InputStream stream)
			throws ParserConfigurationException, SAXException, IOException, XPathExpressionException {
		return (Boolean) evaluateXPath(stream, xpathExpression, XPathConstants.BOOLEAN);
	}

	public static String evaluateToString(String xpathExpression, Node doc) throws XPathExpressionException {
		return (String) evaluateXPath(doc, xpathExpression, XPathConstants.STRING);
	}

	public static NodeList evaluateToNodeList(String xpathExpression, Node doc) throws XPathExpressionException {
		return (NodeList) evaluateXPath(doc, xpathExpression, XPathConstants.NODESET);
	}

	public static Node evaluateToNode(String xpathExpression, Node doc) throws XPathExpressionException {
		return (Node) evaluateXPath(doc, xpathExpression, XPathConstants.NODE);
	}

	public static Double evaluateToNumber(String xpathExpression, Node doc) throws XPathExpressionException {
		return (Double) evaluateXPath(doc, xpathExpression, XPathConstants.NUMBER);
	}

	public static Boolean evaluateToBoolean(String xpathExpression, Node doc) throws XPathExpressionException {
		return (Boolean) evaluateXPath(doc, xpathExpression, XPathConstants.BOOLEAN);
	}
}
